package repository

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"rdiot-demo/internal/eav/domain"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

// entityRepository EntityRepository的实现
type entityRepository struct {
	db *gorm.DB
}

// NewEntityRepository 创建实体仓储实例
func NewEntityRepository(db *gorm.DB) EntityRepository {
	return &entityRepository{
		db: db,
	}
}

// Create 创建实体
func (r *entityRepository) Create(ctx context.Context, entity *domain.Entity, attributes map[string]interface{}) (*domain.Entity, error) {
	err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 1. 创建实体基本信息
		if err := tx.Create(entity).Error; err != nil {
			return fmt.Errorf("创建实体失败: %w", err)
		}

		// 2. 保存属性值
		if len(attributes) > 0 {
			if err := r.saveAttributeValues(tx, entity.ID, attributes); err != nil {
				return fmt.Errorf("保存属性值失败: %w", err)
			}
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return entity, nil
}

// GetByID 根据ID获取实体
func (r *entityRepository) GetByID(ctx context.Context, id uuid.UUID) (*domain.Entity, error) {
	var entity domain.Entity
	err := r.db.WithContext(ctx).Where("id = ?", id).First(&entity).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil
		}
		return nil, fmt.Errorf("获取实体失败: %w", err)
	}
	return &entity, nil
}

// GetByTemplateID 根据模板ID获取实体列表
func (r *entityRepository) GetByTemplateID(ctx context.Context, templateID uuid.UUID, page, size int) ([]*domain.Entity, int64, error) {
	var entities []*domain.Entity
	var total int64

	// 计算总数
	if err := r.db.WithContext(ctx).Model(&domain.Entity{}).Where("template_id = ?", templateID).Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("统计实体数量失败: %w", err)
	}

	// 分页查询
	offset := (page - 1) * size
	err := r.db.WithContext(ctx).Where("template_id = ?", templateID).
		Limit(size).Offset(offset).Find(&entities).Error
	if err != nil {
		return nil, 0, fmt.Errorf("查询实体列表失败: %w", err)
	}

	return entities, total, nil
}

// Update 更新实体
func (r *entityRepository) Update(ctx context.Context, entity *domain.Entity, attributes map[string]interface{}) (*domain.Entity, error) {
	err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 1. 更新实体基本信息
		entity.UpdatedAt = time.Now()
		if err := tx.Save(entity).Error; err != nil {
			return fmt.Errorf("更新实体失败: %w", err)
		}

		// 2. 更新属性值
		if attributes != nil {
			if err := r.updateAttributeValues(tx, entity.ID, attributes); err != nil {
				return fmt.Errorf("更新属性值失败: %w", err)
			}
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return entity, nil
}

// Delete 删除实体
func (r *entityRepository) Delete(ctx context.Context, id uuid.UUID) error {
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 1. 删除属性值
		if err := r.deleteAttributeValues(tx, id); err != nil {
			return fmt.Errorf("删除属性值失败: %w", err)
		}

		// 2. 删除实体
		if err := tx.Delete(&domain.Entity{}, "id = ?", id).Error; err != nil {
			return fmt.Errorf("删除实体失败: %w", err)
		}

		return nil
	})
}

// Query 复杂查询实体
func (r *entityRepository) Query(ctx context.Context, query EntityQuery) ([]*domain.Entity, int64, error) {
	db := r.db.WithContext(ctx).Model(&domain.Entity{})

	// 基本条件过滤
	if query.TemplateID != nil {
		db = db.Where("template_id = ?", *query.TemplateID)
	}
	if query.Name != nil {
		db = db.Where("name LIKE ?", "%"+*query.Name+"%")
	}

	// 属性条件过滤（需要JOIN属性值表）
	for _, condition := range query.Conditions {
		switch condition.DataType {
		case "string":
			db = db.Joins(fmt.Sprintf("JOIN attribute_value_strings avs ON entities.id = avs.entity_id AND avs.attribute_name = '%s'", condition.AttributeName))
			db = r.applyCondition(db, "avs.value", condition.Operator, condition.Value)
		case "number":
			db = db.Joins(fmt.Sprintf("JOIN attribute_value_numbers avn ON entities.id = avn.entity_id AND avn.attribute_name = '%s'", condition.AttributeName))
			db = r.applyCondition(db, "avn.value", condition.Operator, condition.Value)
		case "boolean":
			db = db.Joins(fmt.Sprintf("JOIN attribute_value_booleans avb ON entities.id = avb.entity_id AND avb.attribute_name = '%s'", condition.AttributeName))
			db = r.applyCondition(db, "avb.value", condition.Operator, condition.Value)
		case "datetime":
			db = db.Joins(fmt.Sprintf("JOIN attribute_value_datetimes avd ON entities.id = avd.entity_id AND avd.attribute_name = '%s'", condition.AttributeName))
			db = r.applyCondition(db, "avd.value", condition.Operator, condition.Value)
		case "reference":
			db = db.Joins(fmt.Sprintf("JOIN attribute_value_references avr ON entities.id = avr.entity_id AND avr.attribute_name = '%s'", condition.AttributeName))
			db = r.applyCondition(db, "avr.value", condition.Operator, condition.Value)
		}
	}

	// 排序
	for _, orderBy := range query.OrderBy {
		orderClause := fmt.Sprintf("%s %s", orderBy.Field, orderBy.Direction)
		db = db.Order(orderClause)
	}

	// 计算总数
	var total int64
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("统计查询结果数量失败: %w", err)
	}

	// 分页查询
	var entities []*domain.Entity
	offset := (query.Page - 1) * query.Size
	err := db.Limit(query.Size).Offset(offset).Find(&entities).Error
	if err != nil {
		return nil, 0, fmt.Errorf("查询实体失败: %w", err)
	}

	return entities, total, nil
}

// BatchCreate 批量创建实体
func (r *entityRepository) BatchCreate(ctx context.Context, entities []*domain.Entity, attributesMap map[uuid.UUID]map[string]interface{}) ([]*domain.Entity, error) {
	err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 1. 批量创建实体
		if err := tx.CreateInBatches(entities, 100).Error; err != nil {
			return fmt.Errorf("批量创建实体失败: %w", err)
		}

		// 2. 批量保存属性值
		for _, entity := range entities {
			if attributes, exists := attributesMap[entity.ID]; exists && len(attributes) > 0 {
				if err := r.saveAttributeValues(tx, entity.ID, attributes); err != nil {
					return fmt.Errorf("保存实体 %s 的属性值失败: %w", entity.ID, err)
				}
			}
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return entities, nil
}

// GetAttributes 获取实体的所有属性值
func (r *entityRepository) GetAttributes(ctx context.Context, entityID uuid.UUID) (map[string]interface{}, error) {
	attributes := make(map[string]interface{})

	// 查询字符串属性
	var stringAttrs []domain.AttributeValueString
	if err := r.db.WithContext(ctx).Where("entity_id = ?", entityID).Find(&stringAttrs).Error; err != nil {
		return nil, fmt.Errorf("查询字符串属性失败: %w", err)
	}
	for _, attr := range stringAttrs {
		attributes[attr.AttributeName] = attr.Value
	}

	// 查询数值属性
	var numberAttrs []domain.AttributeValueNumber
	if err := r.db.WithContext(ctx).Where("entity_id = ?", entityID).Find(&numberAttrs).Error; err != nil {
		return nil, fmt.Errorf("查询数值属性失败: %w", err)
	}
	for _, attr := range numberAttrs {
		attributes[attr.AttributeName] = attr.Value
	}

	// 查询布尔属性
	var boolAttrs []domain.AttributeValueBoolean
	if err := r.db.WithContext(ctx).Where("entity_id = ?", entityID).Find(&boolAttrs).Error; err != nil {
		return nil, fmt.Errorf("查询布尔属性失败: %w", err)
	}
	for _, attr := range boolAttrs {
		attributes[attr.AttributeName] = attr.Value
	}

	// 查询日期时间属性
	var datetimeAttrs []domain.AttributeValueDatetime
	if err := r.db.WithContext(ctx).Where("entity_id = ?", entityID).Find(&datetimeAttrs).Error; err != nil {
		return nil, fmt.Errorf("查询日期时间属性失败: %w", err)
	}
	for _, attr := range datetimeAttrs {
		attributes[attr.AttributeName] = attr.Value
	}

	// 查询引用属性
	var refAttrs []domain.AttributeValueReference
	if err := r.db.WithContext(ctx).Where("entity_id = ?", entityID).Find(&refAttrs).Error; err != nil {
		return nil, fmt.Errorf("查询引用属性失败: %w", err)
	}
	for _, attr := range refAttrs {
		attributes[attr.AttributeName] = attr.Value
	}

	// 查询数组属性
	var arrayAttrs []domain.AttributeValueArray
	if err := r.db.WithContext(ctx).Where("entity_id = ?", entityID).Find(&arrayAttrs).Error; err != nil {
		return nil, fmt.Errorf("查询数组属性失败: %w", err)
	}
	for _, attr := range arrayAttrs {
		attributes[attr.AttributeName] = attr.Value
	}

	// 查询JSON属性
	var jsonAttrs []domain.AttributeValueJSON
	if err := r.db.WithContext(ctx).Where("entity_id = ?", entityID).Find(&jsonAttrs).Error; err != nil {
		return nil, fmt.Errorf("查询JSON属性失败: %w", err)
	}
	for _, attr := range jsonAttrs {
		attributes[attr.AttributeName] = attr.Value
	}

	return attributes, nil
}

// saveAttributeValues 保存属性值
func (r *entityRepository) saveAttributeValues(tx *gorm.DB, entityID uuid.UUID, attributes map[string]interface{}) error {
	for name, value := range attributes {
		if err := r.saveAttributeValue(tx, entityID, name, value); err != nil {
			return fmt.Errorf("保存属性 %s 失败: %w", name, err)
		}
	}
	return nil
}

// saveAttributeValue 保存单个属性值
func (r *entityRepository) saveAttributeValue(tx *gorm.DB, entityID uuid.UUID, name string, value interface{}) error {
	now := time.Now()

	switch v := value.(type) {
	case string:
		attr := &domain.AttributeValueString{
			ID:            uuid.New(),
			EntityID:      entityID,
			AttributeName: name,
			Value:         v,
			CreatedAt:     now,
			UpdatedAt:     now,
		}
		return tx.Create(attr).Error

	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
		var numValue float64
		switch nv := v.(type) {
		case int:
			numValue = float64(nv)
		case int8:
			numValue = float64(nv)
		case int16:
			numValue = float64(nv)
		case int32:
			numValue = float64(nv)
		case int64:
			numValue = float64(nv)
		case uint:
			numValue = float64(nv)
		case uint8:
			numValue = float64(nv)
		case uint16:
			numValue = float64(nv)
		case uint32:
			numValue = float64(nv)
		case uint64:
			numValue = float64(nv)
		case float32:
			numValue = float64(nv)
		case float64:
			numValue = nv
		}

		attr := &domain.AttributeValueNumber{
			ID:            uuid.New(),
			EntityID:      entityID,
			AttributeName: name,
			Value:         numValue,
			CreatedAt:     now,
			UpdatedAt:     now,
		}
		return tx.Create(attr).Error

	case bool:
		attr := &domain.AttributeValueBoolean{
			ID:            uuid.New(),
			EntityID:      entityID,
			AttributeName: name,
			Value:         v,
			CreatedAt:     now,
			UpdatedAt:     now,
		}
		return tx.Create(attr).Error

	case time.Time:
		attr := &domain.AttributeValueDatetime{
			ID:            uuid.New(),
			EntityID:      entityID,
			AttributeName: name,
			Value:         v,
			CreatedAt:     now,
			UpdatedAt:     now,
		}
		return tx.Create(attr).Error

	case uuid.UUID:
		attr := &domain.AttributeValueReference{
			ID:            uuid.New(),
			EntityID:      entityID,
			AttributeName: name,
			Value:         v,
			CreatedAt:     now,
			UpdatedAt:     now,
		}
		return tx.Create(attr).Error

	default:
		// 对于数组和JSON类型，存储为JSON
		jsonValue, err := json.Marshal(v)
		if err != nil {
			return fmt.Errorf("序列化JSON值失败: %w", err)
		}

		attr := &domain.AttributeValueJSON{
			ID:            uuid.New(),
			EntityID:      entityID,
			AttributeName: name,
			Value:         json.RawMessage(jsonValue),
			CreatedAt:     now,
			UpdatedAt:     now,
		}
		return tx.Create(attr).Error
	}
}

// updateAttributeValues 更新属性值
func (r *entityRepository) updateAttributeValues(tx *gorm.DB, entityID uuid.UUID, attributes map[string]interface{}) error {
	// 先删除现有属性值
	if err := r.deleteAttributeValues(tx, entityID); err != nil {
		return err
	}

	// 再保存新的属性值
	return r.saveAttributeValues(tx, entityID, attributes)
}

// deleteAttributeValues 删除属性值
func (r *entityRepository) deleteAttributeValues(tx *gorm.DB, entityID uuid.UUID) error {
	// 删除各种类型的属性值
	if err := tx.Where("entity_id = ?", entityID).Delete(&domain.AttributeValueString{}).Error; err != nil {
		return fmt.Errorf("删除字符串属性值失败: %w", err)
	}

	if err := tx.Where("entity_id = ?", entityID).Delete(&domain.AttributeValueNumber{}).Error; err != nil {
		return fmt.Errorf("删除数值属性值失败: %w", err)
	}

	if err := tx.Where("entity_id = ?", entityID).Delete(&domain.AttributeValueBoolean{}).Error; err != nil {
		return fmt.Errorf("删除布尔属性值失败: %w", err)
	}

	if err := tx.Where("entity_id = ?", entityID).Delete(&domain.AttributeValueDatetime{}).Error; err != nil {
		return fmt.Errorf("删除日期时间属性值失败: %w", err)
	}

	if err := tx.Where("entity_id = ?", entityID).Delete(&domain.AttributeValueReference{}).Error; err != nil {
		return fmt.Errorf("删除引用属性值失败: %w", err)
	}

	if err := tx.Where("entity_id = ?", entityID).Delete(&domain.AttributeValueArray{}).Error; err != nil {
		return fmt.Errorf("删除数组属性值失败: %w", err)
	}

	if err := tx.Where("entity_id = ?", entityID).Delete(&domain.AttributeValueJSON{}).Error; err != nil {
		return fmt.Errorf("删除JSON属性值失败: %w", err)
	}

	return nil
}

// applyCondition 应用查询条件
func (r *entityRepository) applyCondition(db *gorm.DB, field, operator string, value interface{}) *gorm.DB {
	switch operator {
	case "eq":
		return db.Where(fmt.Sprintf("%s = ?", field), value)
	case "ne":
		return db.Where(fmt.Sprintf("%s != ?", field), value)
	case "gt":
		return db.Where(fmt.Sprintf("%s > ?", field), value)
	case "gte":
		return db.Where(fmt.Sprintf("%s >= ?", field), value)
	case "lt":
		return db.Where(fmt.Sprintf("%s < ?", field), value)
	case "lte":
		return db.Where(fmt.Sprintf("%s <= ?", field), value)
	case "like":
		return db.Where(fmt.Sprintf("%s LIKE ?", field), "%"+fmt.Sprintf("%v", value)+"%")
	case "in":
		return db.Where(fmt.Sprintf("%s IN ?", field), value)
	default:
		return db
	}
}
